﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using SocketChat.Core.WinForm;
using System.ComponentModel;
using System.Web.Script.Serialization;

namespace SocketChat.Core.Sockets
{
    public class TcpSocketClient
    {
        private Socket _Socket;
        private Action ReceiveMsgAction;
        private Action SendHeartBeatAction;
        private string _Name;
        private Guid _Id;
        private EndPoint _ServerEndPoint;
        public BindingList<Client> OnLineClientList { get; set; }
        #region 显示消息用到的委托和方法
        private Action<ListBoxItem> _AddMsgAction;
        /// <summary>
        /// 显示消息的委托(属性注入)
        /// </summary>
        public Action<ListBoxItem> AddMsgAction {
            get {
                return _AddMsgAction ?? new Action<ListBoxItem>((item) => { });
            }
            set { _AddMsgAction = value; }
        }
        private void AddMsg(string msg) {
            AddMsg(msg, _Name + "(" + _Socket.LocalEndPoint + ")");
        }
        private void AddMsg(string msg, string name) {
            AddMsg(msg, name, DrawType.Msg);
        }
        private void AddMsg(string msg, string name, DrawType drawType) {
            AddMsgAction(new ListBoxItem { Time = DateTime.Now, Body = msg, DrawType = drawType, Name = name });
        }
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serverEndPoint"></param>
        /// <param name="name"></param>
        public TcpSocketClient(EndPoint serverEndPoint, string name) {
            this._Id = Guid.NewGuid();
            this._Name = name;
            this._ServerEndPoint = serverEndPoint;
            OnLineClientList = new BindingList<Client>();
            ReceiveMsgAction = new Action(ReceiveMsg);
            SendHeartBeatAction = new Action(SendHeartBeat);
            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        /// <summary>
        /// 连接到服务器,登记信息到服务器
        /// </summary>
        public void Connect() {
            try {
                _Socket.Connect(_ServerEndPoint);
                var client = new Client { Id = this._Id, HeartBeatTime = DateTime.Now, Name = this._Name };
                Send(new Msg { Id = this._Id, Body = client.ToString(), Header = MsgType.CheckIn });
                AddMsg("连接服务器成功......");
            }
            catch (Exception ex) {
                AddMsg(ex.Message);
                //throw;
            }
            //开始异步接受数据
            ReceiveMsgAction.BeginInvoke(ReceiveMsgCallBack, null);
            //开始异步发送心跳
            SendHeartBeatAction.BeginInvoke(SendHeartBeatCallBack, null);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void Send(Msg msg) {
            msg.Id = this._Id;
            NetworkStream stream = new NetworkStream(_Socket);
            StreamWriter sw = new StreamWriter(stream, Encoding.UTF8);
            if (msg.Header == MsgType.Msg)
                AddMsg(msg.Body);
            if (_Socket.Connected) {
                sw.WriteLine(msg.ToString());
                sw.Flush();
            }
        }

        /// <summary>
        /// 异步接收消息
        /// </summary>
        private void ReceiveMsg() {
            if (_Socket.Connected) {
                NetworkStream stream = new NetworkStream(_Socket);
                StreamReader reader = new StreamReader(stream);
                while (!reader.EndOfStream) {
                    var msg = Msg.Prase(reader.ReadLine().Trim());
                    if (msg.Header == MsgType.HeartBeatRespond) {
                        HandleHeartBeatRespond(msg);
                        //OnLineClientList.Clear();
                        ////msg.Body.Split(',').Select(c => Client.Prase(c)).ToList().ForEach(c => OnLineClientList.Add(c));
                        //AddMsg(msg.Body);
                        //AddMsg(OnLineClientList.Count.ToString());
                    }
                    //AddMsg(msg);
                }
            }
        }

        /// <summary>
        /// 异步接收消息回调
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveMsgCallBack(IAsyncResult ar) {
            ReceiveMsgAction.EndInvoke(ar);
            ReceiveMsgAction.BeginInvoke(ReceiveMsgCallBack, null);
        }

        /// <summary>
        /// 发送心跳
        /// </summary>
        private void SendHeartBeat() {
            Msg msg = new Msg() { Header = MsgType.HeartBeat, Body = string.Empty, Id = this._Id };
            Send(msg);
        }

        /// <summary>
        /// 发送心跳回调
        /// </summary>
        /// <param name="ar"></param>
        private void SendHeartBeatCallBack(IAsyncResult ar) {
            SendHeartBeatAction.EndInvoke(ar);
            System.Threading.Thread.Sleep(1000);
            SendHeartBeatAction.BeginInvoke(SendHeartBeatCallBack, null);
        }

        private void HandleHeartBeatRespond(Msg msg) {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            OnLineClientList.Clear();
            jss.Deserialize<Client[]>(msg.Body).ToList().ForEach(c => this.OnLineClientList.Add(c));
            //AddMsg(msg.Body);
            AddMsg(OnLineClientList.Count.ToString());
        }
    }
}
